// Galaga.java
// Created by Shahein Tajmir
// 3/8/05
// This is the "final" version of Galaga. I have finished. All of it. Yes.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.PathIterator;
import java.util.*;
public class Galaga extends JPanel implements Runnable
{
//******************************************************************************
// Constants
//******************************************************************************
final int SCREEN_WIDTH = 700;
final int SCREEN_HEIGHT = 700;
//******************************************************************************
// Variable Declarations
//******************************************************************************
// Booleans that deal with positioning the player ship
private boolean right, left;
// Booleans that deal with game state
private boolean intro, game, ready, gameOver, win;
// Boolean for if the game is never ending
private boolean neverEnding;
// Integer Variables
private int shots; // Holds the number of shots fired
private int kills; // Holds the number of kills
private int delay = 200; // Holds the number of frames to be displayed
// during "Ready"
private int time = 0; // Holds the number of frames that have been advanced
private int level = 1; // Holds the current level--used in never ending mode
private int score = 0; // Holds the current player score
// Vectors that hold Sprite-Derived Objects
private Vector players = new Vector(); // Vector of Player Ships
private Vector bosses = new Vector(); // Vector of Boss Ships
private Vector butterflies = new Vector(); // Vector of Butterfly Ships
private Vector bees = new Vector(); // Vector of Bee Ships
private Vector playerBullets = new Vector(); // Vector of Player Bullets
private Vector enemyBullets = new Vector(); // Vector of Enemy Bullets
// Object of class Starfield which manages the starfield in the background
private Stars starfield;
// Object that holds the image buffer
private Image imageBuffer;
// Dimension object that holds the screen size
private Dimension d;
// Object of JFrame that holds the game
private JFrame frame;
// Declaration of Thread Object for Timing
private Thread thread;
//******************************************************************************
// Constructor of Galaga
//******************************************************************************
public Galaga()
{
// Create JFrame and set it to close when the X is pressed in upper
// right corner
frame = new JFrame("Galaga");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Sets JFrame background to black
frame.setBackground(Color.BLACK);
// Adds the key listener. The class is defined below
frame.addKeyListener(new gameControlListener());
// This sizes the frame
frame.pack();
// Adds JPanel (Galaga is a child class of JPanel) into JFrame
frame.getContentPane().add(this);
// Dimension Initialization: holds the window size
d = new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
// sets window to correct dimensions
frame.setSize(d);
// Initialize some variables
// Booleans for tracking where in "game stage" we are
intro = true;
game = false;
ready = false;
gameOver = false;
// Booleans for tracking whether the player ship is moving
right = false;
left = false;
// Initializes the image buffer
imageBuffer = createImage(d.width, d.height);
// Instantiates an object of the Stars class, which creates the
// starfield
starfield = new Stars(d);
// Calls the function that assigns all the ship coordinates
// of the main enemy formation
createShips();
// Adds player ship objects to the players vector
// This essentially adds the extra lives and their placement onscreen
players.add(new PlayerShip(d.width / 2, 500));
players.add(new PlayerShip(50 + 50, 600));
players.add(new PlayerShip(50, 600));
// Thread Initialization
thread = new Thread(this);
thread.setPriority(5);
// Thread Start
thread.start();
// Set JFrame visible
frame.show();
}
//******************************************************************************
// Heart of the Game. The Central Infinite Loop, known as run()
//******************************************************************************
public void run()
{
while(true)
{
starfield.moveStars(); // Update star positions in the star field
collisions(); // Perform all sorts of collision detection
prepareImageBuffer(); // Draw the next frame of the game
repaint(); // Paint that next frame to the screen
try
{
Thread.sleep(8); // Sleep the thread for 8 milliseconds
}
catch(InterruptedException e)
{
// Catch the potential interrupted exception and do nothing
}
}
}
//------------------------------------------------------------------------------
// Collision Methods Located Below Here
//------------------------------------------------------------------------------
//******************************************************************************
// Consolidating method that combines all the collision detection into one
//******************************************************************************
protected void collisions()
{
enemyBulletPlayerCollision();
playerBulletEnemyCollision();
playerEnemyShipCollision(bosses); // Ship collisions - Bosses
playerEnemyShipCollision(butterflies); // Ship collisions - Butterflies
playerEnemyShipCollision(bees); // Ship collisions - Bees
}
//******************************************************************************
// Tests for collisions between enemy bullets and player ship
//******************************************************************************
protected void enemyBulletPlayerCollision()
{
// a = each bullet in the vector
for(int a = 0; a < enemyBullets.size(); a++)
{
// Makes sure there are no out of bounds exceptions
if(enemyBullets.size() > 0)
{
// If no player ships remain in the vector, it is game over
if(players.size() == 0)
{
gameOver = true;
game = false;
}
// Makes sure there there are player ships and that the game is
// not in the ready stage
if(players.size() > 0 && !ready)
{
// Temp variable for accessing each bullet
EnemyBullet tempBullet = (EnemyBullet) enemyBullets.get(a);
// Temp variable for accessing the current player ship
PlayerShip currentPlayer = (PlayerShip) players.get(0);
// If the bullet's y-coordinate is greater than the player
// ship's top coordinate, and the bullet's top y-coordinate
// is less than the player ship's bottom coordinate.
if(tempBullet.getYCoordinate()
+ tempBullet.getDimension().height >
currentPlayer.getYCoordinate()
&& tempBullet.getYCoordinate() < currentPlayer
.getYCoordinate() + currentPlayer
.getDimension().height)
{
// If the bullet's right x-coordinate is greater than
// the player ship's left coordinate, and the bullet's
// left coordinate is less than the player ship's
// right coordinate.
if(tempBullet.getXCoordinate() > currentPlayer
.getXCoordinate()
& tempBullet.getXCoordinate() <
currentPlayer.getXCoordinate()
+ currentPlayer.getDimension().width)
{
// Remove the enemy bullet
enemyBullets.remove(a);
// Remove the player ship
players.remove(0);
// If there are still lives left
if(players.size() != 0)
{
// Start the Ready stage
ready = true;
// Stop the game temporarily
game = false;
// Take the next ship and move it to the center
Sprite tempShip = (Sprite) players.get(0);
tempShip.setPosition(d.width / 2, 500);
}
// Forced frame repaint
repaint();
}
}
}
}
}
}
//******************************************************************************
// Tests for collisions between player bullets and enemy ships
//******************************************************************************
protected void playerBulletEnemyCollision()
{
//**************************************************************************
// Tests for collisions with Boss Ships
//**************************************************************************
// i = each boss ship in the vector
for(int i = 0; i < bosses.size(); i++)
{
// a = each bullet in the vector
for(int a = 0; a < playerBullets.size(); a++)
{
// Makes sure that the vectors are not empty
if(playerBullets.size() != 0 && bosses.size() != 0)
{
// Temp variable for accessing each bullet
PlayerBullet tempBullet = (PlayerBullet) playerBullets.get(a);
// Temp variable for accessing each BossShip
BossShip tempShip = (BossShip) bosses.get(i);
// If the bullet's top y-coordinate is below the enemy's top
// y-coordinate and the bullet's top y-coordinate is above
// the enemy's bottom y-coordinate
if(tempBullet.getYCoordinate() > tempShip.getYCoordinate()
& tempBullet.getYCoordinate() < tempShip
.getYCoordinate() + tempShip.getDimension().
height)
{
// If the bullet's left x-coordinate is right of the
// enemy's left x-coordinate and the bullet's left
// x-coordinate is left of the enemy's right
// x-coordinate
if(tempBullet.getXCoordinate() > tempShip.getXCoordinate()
&& tempBullet.getXCoordinate() <
tempShip.getXCoordinate() + tempShip
.getDimension().width)
{
// If the Boss Ship has no hits
if(tempShip.getHits() < 1)
{
// Increment its hit counter
tempShip.hit();
// Remove the PlayerBullet from the Vector
playerBullets.remove(a);
// Increment the score value
score += tempShip.getScore() / 2;
}
// If the Boss Ship has 1 hit
else if(tempShip.getHits() == 1)
{
// Remove the BossShip from the Vector
bosses.remove(i);
// Remove the PlayerBullet from the Vector
playerBullets.remove(a);
// Increment the kills
kills++;
// Increment the score value
score += tempShip.getScore();
}
}
}
}
}
}
//**************************************************************************
// Tests for collisions with ButterflyShips
//**************************************************************************
// i = each ButterflyShip in the vector
for(int i = 0; i < butterflies.size(); i++)
{
// a = each bullet in the vector
for(int a = 0; a < playerBullets.size(); a++)
{
// Makes sure that the vectors are not empty
if(playerBullets.size() != 0 && butterflies.size() != 0)
{
// Temp variable for accessing each bullet
PlayerBullet tempBullet = (PlayerBullet) playerBullets.get(a);
// Temp variable for accessing each ButterflyShip
Sprite tempShip = (Sprite) butterflies.get(i);
// If the bullet's top y-coordinate is below the enemy's top
// y-coordinate and the bullet's top y-coordinate is above
// the enemy's bottom y-coordinate
if(tempBullet.getYCoordinate() > tempShip.getYCoordinate()
& tempBullet.getYCoordinate() < tempShip
.getYCoordinate() + tempShip.getDimension().
height)
{
// If the bullet's left x-coordinate is right of the
// enemy's left x-coordinate and the bullet's left
// x-coordinate is left of the enemy's right
// x-coordinate
if(tempBullet.getXCoordinate() > tempShip.getXCoordinate()
&& tempBullet.getXCoordinate() <
tempShip.getXCoordinate() + tempShip
.getDimension().width)
{
// Remove the Butterfly from the Vector
butterflies.remove(i);
// Remove the Bullet from the Vector
playerBullets.remove(a);
// Increment the Kills Value
kills++;
// Increment the Score Value
score += tempShip.getScore();
}
}
}
}
}
//**************************************************************************
// Tests for collisions with BeeShips
//**************************************************************************
// i = each BeeShip in the vector
for(int i = 0; i < bees.size(); i++)
{
// a = each bullet in the vector
for(int a = 0; a < playerBullets.size(); a++)
{
// Makes sure that the vectors are not empty
if(playerBullets.size() != 0 && bees.size() != 0)
{
// Temp variable for accessing each bullet
PlayerBullet tempBullet = (PlayerBullet) playerBullets.get(a);
// Temp variable for accessing each BeeShip
Sprite tempShip = (Sprite) bees.get(i);
// If the bullet's top y-coordinate is below the enemy's top
// y-coordinate and the bullet's top y-coordinate is above
// the enemy's bottom y-coordinate
if(tempBullet.getYCoordinate() > tempShip.getYCoordinate()
& tempBullet.getYCoordinate() < tempShip
.getYCoordinate() + tempShip.getDimension().
height)
{
// If the bullet's left x-coordinate is right of the
// enemy's left x-coordinate and the bullet's left
// x-coordinate is left of the enemy's right
// x-coordinate
if(tempBullet.getXCoordinate() > tempShip.getXCoordinate()
&& tempBullet.getXCoordinate() <
tempShip.getXCoordinate() + tempShip
.getDimension().width)
{
// Remove the Bee from the Vector
bees.remove(i);
// Remove the Bullet from the Vector
playerBullets.remove(a);
// Increment the kills value
kills++;
// Increment the score value
score += tempShip.getScore();
}
}
}
}
}
}
//******************************************************************************
// Method that tests for collisions between player and enemy ships
//******************************************************************************
protected void playerEnemyShipCollision(Vector tempVector)
{
// i = each enemy in the Vector
for(int i = 0; i < tempVector.size(); i++)
{
// Test for an empty enemy vector
if(tempVector.size() > 0)
{
// If no players exist, its game over
if(players.size() == 0)
{
gameOver = true;
game = false;
}
// Test for an empty player vector and makes sure we are not in
// the Ready state
if(players.size() > 0 && !ready)
{
// Temp sprite for accessing each enemy ship
Sprite tempShip = (Sprite) tempVector.get(i);
// Temp ship for accessing the current player ship
PlayerShip currentPlayer = (PlayerShip) players.get(0);
// If the current player's right x-coordinate is right of the
// enemy's left coordinate, and the players x-coordinate is
// left of the enemy's right x-coordinate
if((currentPlayer.getXCoordinate()
+ currentPlayer.getDimension().width >
tempShip.getXCoordinate())
&& (currentPlayer.getXCoordinate() < tempShip
.getXCoordinate() + tempShip.getDimension().width))
{
// If the current player's bottom y-coordinate is below
// the enemy's top y-coordinate, and the current player's
// top y-coordinate is above the enemy's bottom
// y-coordinate
if(((currentPlayer.getYCoordinate() + currentPlayer
.getDimension().height) > (tempShip
.getYCoordinate()))
&& ((currentPlayer.getYCoordinate() < tempShip
.getYCoordinate() + tempShip.getDimension()
.height)))
{
// Remove the player ship from the vector
players.remove(0);
// Remove the enemy ship from the vector
tempVector.remove(i);
// If there are still lives for the player
if(players.size() != 0)
{
// Enter the Ready state
ready = true;
// Temporarily exit the Game state
game = false;
// Move the next ship in the vector to the
// playable area
Sprite tempShip2 = (Sprite) players.get(0);
tempShip2.setPosition(d.width / 2, 500);
}
// Forced repaint to update any disappearing ships
repaint();
}
}
}
}
}
}
//------------------------------------------------------------------------------
// Methods that deal with Curve Generation Located Below Here
//------------------------------------------------------------------------------
//******************************************************************************
// Method that goes through the process of moving each ship.
// It either moves a ship along its vector of points OR
// It calls for the creation of a curve and the assignment of the points OR
// It simply updates the timer for the ship
//******************************************************************************
protected boolean moveShips(Vector tempVector, Graphics g)
{
// Number of ships of a given class that are moving
int counter = 0;
// Check how many ships are moving at a given time
// i = each ship in the Vector
for(int i = 0; i < tempVector.size(); i++)
{
// Temp variable for accessing the ship from the Vector
Sprite tempShip = (Sprite) tempVector.get(i);
// If the ship is moving or attacking
if(tempShip.isAttacking() || tempShip.isRetreating())
// Update the counter
counter++;
}
// For each ship in the vector
for(int i = 0; i < tempVector.size(); i++)
{
// Temp variable for accessing the ship from the Vector
Sprite tempShip = (Sprite) tempVector.get(i);
// Calls the CheckTime method of each ship. This goes through and
// checks if enough time has passed for a ship to start moving.
// If it has, the ship will be set to attack, and it will
// return true.
if(tempShip.checkTime())
{
// If the ship is attacking and a null array
if(tempShip.isAttacking() && tempShip.attackPoints == null)
{
// If there are fewer ships on screen than the level
if(counter < level && !ready)
assignCurve(g, tempShip); // Assign a curve
// Move the ship along its curve
tempShip.attackShip(enemyBullets, (PlayerShip) players.get(0));
}
// If the ship is attacking and has no points assigned
if(tempShip.isAttacking() && tempShip
.attackPoints[tempShip.attackPoints.length - 1] == null)
{
// If there are fewer ships on screen than the level
if(counter < level && !ready)
assignCurve(g, tempShip); // Assign a curve
// Move the ship along its curve
tempShip.attackShip(enemyBullets, (PlayerShip) players.get(0));
}
// If the ship is attacking
if(tempShip.isAttacking())
{
// Move the ship along its curve
tempShip.attackShip(enemyBullets, (PlayerShip) players.get(0));
}
// If the ship is retreating
if(tempShip.isRetreating())
{
// Move the ship along its curve
tempShip.retreatShip();
}
}
}
if(counter == 0) // If no ships are moving, return true
return true;
else // Otherwise, return false
return false;
}
//******************************************************************************
// Method that assigns the curve to the enemy ship
//******************************************************************************
protected void assignCurve(Graphics g, Sprite tempShip)
{
Vector tempPoints = new Vector(); // Creates a temporary vector of points
Point points2[]; // Creates a temporary array of points
// Creates a temporary Graphics2D Context used to fill in the path
Graphics2D g2 = (Graphics2D) g;
// Sets the enemy ship moving
tempShip.setMoving(true);
// Creates the Bezier Curve into a Shape Object
Shape curve = generateCurve((PlayerShip) players.get(0), tempShip);
// Creates a path iterator which will go point by point over the boundary
PathIterator p = curve.getPathIterator(null);
// Creates a flattening path iterator which extracts the points
FlatteningPathIterator f = new FlatteningPathIterator(p, 0.02);
// While it is not done iterating
while(!f.isDone())
{
// Create a temp object to extract the points
double[] points = new double[6];
switch(f.currentSegment(points))
{
// When the iterator has found a point
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
// Fill a circle at the point
g2.fill(new Ellipse2D.Double(points[0], points[1], 3, 3));
// Add the point to the vector
tempPoints.add(new Point((int) points[0], (int) points[1]));
}
// Go to the next point
f.next();
}
// Creates an array based on the size of the Vector
points2 = new Point[tempPoints.size()];
// Goes through the Vector and assigns the points to the array
for(int i = 0; i < tempPoints.size(); i++)
{
points2[i] = (Point) tempPoints.get(i);
}
// Passes the array to the ship, which will set the attack and
// retreat points
tempShip.setCurve(points2);
// Sets ship to attack
tempShip.setAttack(true);
}
//******************************************************************************
// Generates the Curve when passed the player and enemy ships
//******************************************************************************
protected Shape generateCurve(Sprite player, Sprite enemy)
{
// Sets a null curve: Temporary
Shape curve = null;
// If the Enemy is on the left side of the screen,
// use one set of control points
if(enemy.getXCenter() < d.width / 2)
curve = new CubicCurve2D.Double(enemy.getXCenter(), enemy.getYCenter(),
d.width, enemy.getYCenter(),
enemy.getXCenter(), d.height,
player.getXCenter(), player.getYCenter());
// If the enemy is on the right side of the screen,
// use an alternate set of points
if(enemy.getXCenter() >= d.width / 2)
curve = new CubicCurve2D.Double(enemy.getXCenter(), enemy.getYCenter(),
0, enemy.getYCenter(),
enemy.getXCenter(), d.height,
player.getXCenter(), player.getYCenter());
return curve; // Return the generate curve
}
//------------------------------------------------------------------------------
// Methods that move Bullets Located Below Here
//------------------------------------------------------------------------------
//******************************************************************************
// Consolidating Method that puts the bullet managing into one Method
//******************************************************************************
protected void moveBullets(Graphics g)
{
movePlayerBullets(g); // Player Bullets
moveEnemyBullets(g); // Enemy Bullets
}
//*****************************************************************************************
// Method that updates the position of the player bullets
//*****************************************************************************************
protected void movePlayerBullets(Graphics g)
{
for(int i = 0; i < playerBullets.size(); i++)
{
// i = each player bullet in the vector
// Temp variable for accessing each player bullet in the vector
PlayerBullet temp = (PlayerBullet) playerBullets.get(i);
// Move the bullet up 12 pixels
temp.translate(0, -12);
// If the bullet has passed the top of the screen, remove the bullet
if(temp.getYCoordinate() < 1)
{
playerBullets.remove(i--);
}
// Otherwise, draw the bullet
else
{
temp.draw(g, temp.getXCoordinate(), temp.getYCoordinate());
}
}
}
//*****************************************************************************************
// Method that updates the position of the enemy bullets
//*****************************************************************************************
protected void moveEnemyBullets(Graphics g)
{
for(int i = 0; i < enemyBullets.size(); i++)
{
// i = each bullet in the vector
// Temp variable for accessing each bullet in the Vector
EnemyBullet temp = (EnemyBullet) enemyBullets.get(i);
// Update each bullet's position in the vector
temp.updatePosition();
// If the bullet has gone beyond the bottom edge of the screen, remove it
if(temp.getYCoordinate() > d.height)
{
enemyBullets.remove(i--);
}
// Otherwise, draw the bullet at its new updated location
else
{
temp.draw(g, temp.getXCoordinate(), temp.getYCoordinate());
}
}
}
//------------------------------------------------------------------------------
// Assorted Helper-Methods Located Below Here
//------------------------------------------------------------------------------
//*****************************************************************************************
// Method that draws the vector of ships passed to it
//*****************************************************************************************
protected void drawShip(Graphics g, Vector tempVector)
{
for(int i = 0; i < tempVector.size(); i++)
{
// i = each individual ship in the Vector
// Temp variable for accessing each ship in the Vector
Sprite tempShip = (Sprite) tempVector.get(i);
// Draws each ship
tempShip.draw(g, tempShip.getXCoordinate(), tempShip.getYCoordinate());
}
}
//******************************************************************************
// Method that Initializes all the enemy vectors
//******************************************************************************
protected void createShips()
{
clearVectors(); // Clear all the vectors in the game
// Row of Boss Ships
bosses.add(new BossShip((d.width / 2) - 2 * 45, 100));
bosses.add(new BossShip((d.width / 2) - 1 * 45, 100));
bosses.add(new BossShip((d.width / 2) + 0 * 45, 100));
bosses.add(new BossShip((d.width / 2) + 1 * 45, 100));
// Row 1 of Butterflies
butterflies.add(new ButterflyShip((d.width / 2) - 4 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) - 3 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) - 2 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) - 1 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) + 0 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) + 1 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) + 2 * 45, 100 + 48));
butterflies.add(new ButterflyShip((d.width / 2) + 3 * 45, 100 + 48));
// Row 2 of Butterflies
butterflies.add(new ButterflyShip((d.width / 2) - 4 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) - 3 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) - 2 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) - 1 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) + 0 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) + 1 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) + 2 * 45, 100 + 48 + 30));
butterflies.add(new ButterflyShip((d.width / 2) + 3 * 45, 100 + 48 + 30));
// Row 1 of Bees
bees.add(new BeeShip((d.width / 2) - 5 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 4 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 3 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 2 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 1 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 0 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 1 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 2 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 3 * 45, 100 + 48 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 4 * 45, 100 + 48 + 30 + 30));
// Row 2 of Bees
bees.add(new BeeShip((d.width / 2) - 5 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 4 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 3 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 2 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 1 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) - 0 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 1 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 2 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 3 * 45, 100 + 48 + 30 + 30 + 30));
bees.add(new BeeShip((d.width / 2) + 4 * 45, 100 + 48 + 30 + 30 + 30));
}
//******************************************************************************
// Method that clears all the vectors and reinitializes the player ships
//******************************************************************************
protected void clearVectors()
{
// Clear the vectors
bees.clear(); // Bees
bosses.clear(); // Bosses
butterflies.clear(); // Butterflies
// This is how the player's lives are replenished on each level in
// never-ending mode
players.clear();
players.add(new PlayerShip(d.width / 2, 500));
players.add(new PlayerShip(50 + 50, 600));
players.add(new PlayerShip(50, 600));
// Clear the bullet vectors as well
enemyBullets.clear();
playerBullets.clear();
}
//------------------------------------------------------------------------------
// Painting Functions Located Below Here
//------------------------------------------------------------------------------
//******************************************************************************
// Overridden Paint Method that paints the buffer to the screen
//******************************************************************************
public void paint(Graphics g)
{
g.drawImage(imageBuffer, 0, 0, null);
}
//******************************************************************************
// Overridden Update Method that calls paint() for smoother animation
//******************************************************************************
public void update(Graphics g)
{
paint(g);
}
//******************************************************************************
// Method that creates the image buffer. Think of this method as the
// "paint" method.
//******************************************************************************
protected void prepareImageBuffer()
{
// Gets a graphical context -- the buffered image
Graphics g = imageBuffer.getGraphics();
// Clears screen
g.setColor(Color.black);
g.fillRect(0, 0, d.width, d.height);
// Calls the method of starfield that draws the stars to the buffer
starfield.drawStars(g);
if(intro) // If in intro stage of game, call the paintIntro() method
{
paintIntro(g);
}
if(game) // If in game stage of game, call the paintGame() method
{
paintGame(g);
}
if(ready) // If in ready stage of game, call the paintReady() method
{
paintReady(g);
}
if(gameOver) // If in over stage of game, call the paintGameOver() method
{
paintGameOver(g);
}
if(win) // If in win stage of game, call the paintWin() method
{
paintWin(g);
}
}
//******************************************************************************
// Paints the Intro Screen
//******************************************************************************
protected void paintIntro(Graphics g)
{
// Vector of the sprites on screen for scoring
Vector sprites = new Vector();
// Fonts used on screen
Font galaga = new Font("Papyrus", Font.BOLD | Font.ITALIC, 26);
Font title = new Font("Papyrus", Font.PLAIN, 18);
Font scores = new Font("Arial", Font.PLAIN, 18);
Font instructions = new Font("Arial", Font.PLAIN, 12);
// Adds one of each sprite to the Sprites Vector
sprites.add(new BossShip(250, 150));
sprites.add(new ButterflyShip(253, 205));
sprites.add(new BeeShip(253, 240));
// Draws Vector contents
drawShip(g, sprites);
// Draws title of game
g.setFont(galaga);
g.setColor(Color.ORANGE);
g.drawString("Galaga", 310, 50);
// Draws scoring info
g.setFont(title);
g.drawString("Scoring", 320, 140);
g.setFont(title);
g.setColor(Color.white);
g.drawString("----------- 200", 320, 180);
g.drawString("----------- 150", 320, 220);
g.drawString("----------- 100", 320, 255);
// Draws instructions
g.setColor(Color.ORANGE);
g.drawString("Instructions", 50, 300);
g.setFont(instructions);
g.setColor(Color.white);
g.drawString("Use the arrow keys to move left and right. " +
"Press Spacebar to fire.", 200, 300);
g.drawString("This game is merely a clone of the famous game " +
"with the same name.", 200, 315);
g.drawString("As such, certain aspects of the original have not " +
"been implemented.", 200, 330);
g.drawString("However, this is still fun and rather difficult.", 200, 345);
g.drawString("There are two game options: " +
"Never Ending and Single-Level", 200, 375);
g.drawString("Press 1 to play Never Ending Mode", 210, 390);
g.drawString("Press 2 to play Single-Level Mode", 210, 405);
}
//******************************************************************************
// Paints the Game Screens
//******************************************************************************
protected void paintGame(Graphics g)
{
// Makes sure that there are lives for the player
if(players.size() != 0)
{
// Draw the score and level information
Font text = new Font("Papyrus", Font.PLAIN, 14);
g.setColor(Color.white);
g.setFont(text);
g.drawString("Score: " + score, 20, 20);
g.drawString("Level: " + level, d.width - 100, 20);
g.setColor(Color.blue);
// Move the bullets
moveBullets(g);
drawShip(g, players); // Draw all the player ships
drawShip(g, bosses); // Draw the Boss Ships
moveShips(bosses, g); // Move the Boss Ships
drawShip(g, butterflies); // Draw the Butterfly Ships
moveShips(butterflies, g); // Move the Butterfly Ships
drawShip(g, bees); // Draw the Bee Ships
moveShips(bees, g); // Move the Bee Ships
// Temp Variable for accessing the current player ship
PlayerShip currentPlayer = (PlayerShip) players.get(0);
// If ship is moving right and it's right side is less than the
// right edge
if(right && (currentPlayer.getRightSide() < 680))
{
// Move ship 5 pixels right
currentPlayer.translate(5, 0);
}
// If ship is moving left and it's left side is greater than the
// left edge
if(left && currentPlayer.getLeftSide() > 2)
{
// Move ship 5 pixels right
currentPlayer.translate(-5, 0);
}
// If in never-ending mode, and all the enemies are gone,
// advance to the next level
if(neverEnding)
{
if(bosses.size() == 0 && bees.size() == 0 && butterflies.size() == 0)
{
game = false;
ready = true;
level++;
createShips();
}
}
// Otherwise, end the game when all the enemies are gone
else
{
if(bosses.size() == 0 && bees.size() == 0 && butterflies.size() == 0)
{
game = false;
win = true;
}
}
}
}
//******************************************************************************
// Paints the Ready Screens
//******************************************************************************
protected void paintReady(Graphics g)
{
// Booleans for determining if any ships are moving
boolean boss, bee, fly;
// Draw Score and Level information
Font text = new Font("Papyrus", Font.PLAIN, 14);
g.setColor(Color.white);
g.setFont(text);
g.drawString("Score: " + score, 20, 20);
g.drawString("Level: " + level, d.width - 100, 20);
g.setColor(Color.blue);
// Move all bullets on screen
moveBullets(g);
// Draw the remaining player ships
if(players.size() != 0)
for(int i = 1; i < players.size(); i++)
{
Sprite tempShip = (Sprite) players.get(i);
tempShip.draw(g, tempShip.getXCoordinate(), tempShip
.getYCoordinate());
}
drawShip(g, bosses); // Draw the Boss Ships
boss = moveShips(bosses, g); // Determine if any bosses are moving
drawShip(g, butterflies); // Draw the Butterfly Ships
fly = moveShips(butterflies, g);// Determine if any butterflies are moving
drawShip(g, bees); // Draw the Bee Ships
bee = moveShips(bees, g); // Determine if any bees are moving
// If no ships are moving: Ready was triggered by a player loss of life
if(boss && bee && fly)
{
// Draw "ready"
g.drawString("Ready", d.width / 2, d.height / 2);
// Draw player ships
drawShip(g, players);
// If the screen has shown long enough, go back to game
if(time == delay)
{
ready = false;
game = true;
time = 0;
}
else // Otherwise, increment time
{
time++;
}
}
// If no ships are moving: Ready was triggered by completion of level
if(bosses.size() == 0 && bees.size() == 0 && butterflies.size() == 0)
{
// If the screen has shown long enough, go back to game
if(time == delay)
{
ready = false;
game = true;
time = 0;
}
else // Otherwise, increment time
{
time++;
}
}
}
//******************************************************************************
// Paints the GameOver Screen
//******************************************************************************
protected void paintGameOver(Graphics g)
{
// Font declarations
Font galaga = new Font("Papyrus", Font.BOLD | Font.ITALIC, 26);
Font title = new Font("Papyrus", Font.PLAIN, 18);
Font text = new Font("Papyrus", Font.PLAIN, 14);
// Clear the screen
Dimension d = frame.getSize();
g.setColor(Color.black);
g.fillRect(0, 0, d.width, d.height);
// Draw the relevant statistics
g.setFont(galaga);
g.setColor(Color.ORANGE);
g.drawString("Game Over", 300, 100);
g.setFont(title);
g.setColor(Color.white);
g.drawString("Shots: ", 200, 200);
g.setFont(text);
String string = "" + shots;
g.drawString(string, 275, 200);
g.drawString("Enemies Destroyed: ", 200, 230);
g.setFont(text);
String string2 = "" + kills;
g.drawString(string2, 350, 230);
g.drawString("Hit Percentage: ", 200, 260);
g.setFont(text);
if(shots == 0)
shots = 1;
String string3 = "" + (((double) kills / shots) * 100) + '%';
g.drawString(string3, 340, 260);
g.drawString("Score: ", 200, 290);
g.drawString("" + score, 340, 290);
// If enough time has passed, return to the intro screen
if(time > delay)
{
gameOver = false;
intro = true;
clearVectors();
time = 0;
score = 0;
}
// Otherwise, increment the counter
else
{
time++;
}
}
//******************************************************************************
// Paints the Win Screens
//******************************************************************************
protected void paintWin(Graphics g)
{
// Font declarations
Font gameOver = new Font("Papyrus", Font.BOLD | Font.ITALIC, 26);
Font title = new Font("Papyrus", Font.PLAIN, 18);
Font text = new Font("Papyrus", Font.PLAIN, 14);
// Clear the screen
Dimension d = frame.getSize();
g.setColor(Color.black);
g.fillRect(0, 0, d.width, d.height);
// Draw the relevant statistics
g.setFont(gameOver);
g.setColor(Color.ORANGE);
g.drawString("You Won", 300, 100);
g.setFont(title);
g.setColor(Color.white);
g.drawString("Shots: ", 200, 200);
g.setFont(text);
String string = "" + shots;
g.drawString(string, 275, 200);
g.drawString("Enemies Destroyed: ", 200, 230);
g.setFont(text);
String string2 = "" + kills;
g.drawString(string2, 350, 230);
g.drawString("Hit Percentage: ", 200, 260);
g.setFont(text);
if(shots == 0)
shots = 1;
String string3 = "" + (((double) kills / shots) * 100) + '%';
g.drawString(string3, 340, 260);
g.drawString("Score: ", 200, 290);
g.drawString("" + score, 340, 290);
// If enough time has passed, return to the intro screen
if(time > delay)
{
win = false;
intro = true;
clearVectors();
time = 0;
score = 0;
}
// Otherwise, increment the counter
else
{
time++;
}
}
//******************************************************************************
// gameControlListener Class - Encapsulates the key listener as a seperate
// class
//******************************************************************************
public class gameControlListener implements KeyListener
{
//******************************************************************************
// Empty Constructor that does nothing
//******************************************************************************
public gameControlListener()
{
}
//******************************************************************************
// Keys Pressed
//******************************************************************************
public void keyPressed(KeyEvent ke)
{
// Left and Right controls
if(ke.getKeyCode() == KeyEvent.VK_RIGHT)
right = true;
if(ke.getKeyCode() == KeyEvent.VK_LEFT)
left = true;
// Game Start Controls: Never-Ending
if((intro || win || gameOver) && (ke.getKeyCode() == KeyEvent.VK_1 ||
ke.getKeyCode() == KeyEvent.VK_NUMPAD1))
{
neverEnding = true;
intro = false;
win = false;
gameOver = false;
ready = true;
createShips();
players.clear();
players.add(new PlayerShip(d.width / 2, 500));
players.add(new PlayerShip(50 + 50, 600));
players.add(new PlayerShip(50, 600));
level = 1;
repaint();
}
// Game Start Controls: 1 Level
if((intro || win || gameOver) && (ke.getKeyCode() == KeyEvent.VK_2 ||
ke.getKeyCode() == KeyEvent.VK_NUMPAD2))
{
neverEnding = false;
intro = false;
win = false;
gameOver = false;
ready = true;
players.clear();
players.add(new PlayerShip(d.width / 2, 500));
players.add(new PlayerShip(50 + 50, 600));
players.add(new PlayerShip(50, 600));
createShips();
repaint();
}
}
//******************************************************************************
// Keys Released
//******************************************************************************
public void keyReleased(KeyEvent ke)
{
// Left and Right controls
if(ke.getKeyCode() == KeyEvent.VK_RIGHT)
right = false;
if(ke.getKeyCode() == KeyEvent.VK_LEFT)
left = false;
// Player firing of bullets
if(ke.getKeyCode() == KeyEvent.VK_SPACE && !ready)
{
// Allows for only 2 bullets on screen at a time
if(playerBullets.size() < 2)
{
// Temp Player Bullet
PlayerBullet temp = new PlayerBullet(0, 0);
// Temp variable to access current player
PlayerShip currentPlayer = (PlayerShip) players.get(0);
// Create X and Y coordinates based on player position
int x = currentPlayer.getXCenter();
int y = currentPlayer.getYCoordinate()
- temp.getDimension().height;
// Create new bullet
temp = new PlayerBullet(x, y);
// Add bullet to vector
playerBullets.add(temp);
// Increment Shots Value
shots++;
}
}
}
//******************************************************************************
// Keys Typed - I have no idea what this does... So it does nothing
//******************************************************************************
public void keyTyped(KeyEvent ke)
{
}
}
//******************************************************************************
// Hey, there is that main method!!! I know you've been looking for it...
//******************************************************************************
public static void main(String[] args)
{
// Creates a new instance of the class Galaga
Galaga SHAHEIN_HAS_FINISHED_THIS_GAME_FINALLY = new Galaga();
// I think that line is rather self-explanatory...
}
}